package com.leantech.android.browser.browser.web

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.webkit.CookieManager
import android.webkit.WebSettings
import androidx.webkit.WebSettingsCompat
import androidx.webkit.WebViewFeature
import com.cscj.android.repository.repo.config.WebViewConfig
import com.cscj.android.repository.settings.model.SettingConstants
import com.cscj.android.utils.LOG
import com.leantech.android.browser.BuildConfig

import com.leantech.android.browser.browser.BrowserDelegate
import com.leantech.android.browser.browser.WebViewCallback
import com.leantech.android.browser.browser.WebViewController
import com.leantech.android.browser.browser.inject.disableReaderMode
import com.leantech.android.browser.browser.inject.eval
import com.leantech.android.browser.browser.inject.getReaderCss
import com.leantech.android.browser.browser.inject.getReaderModeBodyText
import com.leantech.android.browser.browser.inject.getReaderModeJs
import com.leantech.android.browser.browser.inject.injectCss
import com.leantech.android.browser.browser.inject.makeCustomBackgroundCss
import com.leantech.android.browser.browser.inject.makeCustomTextColorCss
import com.leantech.android.browser.browser.inject.replaceWithReaderModeBody
import com.leantech.android.browser.browser.inject.webContentScrollTop
import com.qmuiteam.qmui.skin.QMUISkinManager
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


@SuppressLint("ViewConstructor")
class RocketWebView(
    context: Context, var config: WebViewConfig = WebViewConfig()
) : NestedScrollWebView2(context), WebViewController {

    var browserDelegate: BrowserDelegate? = null
    var webViewCallback: WebViewCallback? = null

    private var onScrollChangeListener: OnScrollChangeListener? = null

    var isSelectingText = false

    var clearHistory = false

    private var inReaderMode = false

    private val webViewClient: RocketWebViewClient = RocketWebViewClient(this)
    private val webChromeClient: RocketWebChromeClient = RocketWebChromeClient(this)

    private val cookieManager = CookieManager.getInstance()

    private val skinChangeListener =
        QMUISkinManager.OnSkinChangeListener { skinManager, oldSkin, newSkin ->
            updateDarkMode(SettingConstants.DarkModeFollowSystem) //WebView的暗黑模式只会跟随系统
        }

    init {
        initWebView()
        initWebSettings()
        initConfig()
    }

    private fun initWebView() {
        if (BuildConfig.DEBUG) {
            setWebContentsDebuggingEnabled(true)
        }
        setWebViewClient(webViewClient)
        setWebChromeClient(webChromeClient)
        setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
//            val uri = Uri.parse(url)
//            val request = DownloadManager.Request(uri)
//            val fileName = uri.lastPathSegment ?: "${System.currentTimeMillis()}.files"
//            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
//            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
//            val dm = context.getSystemService(Application.DOWNLOAD_SERVICE) as DownloadManager
//            dm.enqueue(request)
        }

        setupJsWebInterface()
    }

    private fun initConfig() {
        updateUserAgent(config.userAgent)
        with(settings) {
            textZoom = config.fontSize
            javaScriptEnabled = config.enableJavascript
            javaScriptCanOpenWindowsAutomatically = config.enableJavascript
            mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
            enableCookieSupport(config.enableCookie)
        }

        updateImageMode(config.imageMode)
        updateDarkMode(config.darkMode)
    }

    /**
     * 修改web 样式
     */
    fun updateCssStyle() {
        val cssStyle = buildString {
            append(makeCustomBackgroundCss(config.backgroundColor))
            append(makeCustomTextColorCss(config.textColor))
            if (config.readerMode) {//TODO 阅读模式，需要配合js一起食用
                append(String(getReaderCss()), Charsets.UTF_8)
            }
        }
        if (cssStyle.isNotBlank()) {
            injectCss(cssStyle)
        }
    }

    private fun setupJsWebInterface() {
        addJavascriptInterface(JsWebInterface(this), "androidApp")
    }

    override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
        super.onScrollChanged(l, t, oldl, oldt)
        onScrollChangeListener?.onScrollChange(t, oldt)
    }

    fun setScrollChangeListener(onScrollChangeListener: OnScrollChangeListener?) {
        this.onScrollChangeListener = onScrollChangeListener
    }

    interface OnScrollChangeListener {
        fun onScrollChange(scrollY: Int, oldScrollY: Int)
    }

    //webview default settings.
    private fun initWebSettings() {
        with(settings) {
            builtInZoomControls = true
            allowFileAccess = true
            databaseEnabled = true
            cacheMode = WebSettings.LOAD_DEFAULT
            domStorageEnabled = true
            allowContentAccess = true

            displayZoomControls = false
            setSupportZoom(true)
            loadWithOverviewMode = false
            useWideViewPort = false
            mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }
    }

    private fun enableCookieSupport(enable: Boolean) {
        with(cookieManager) {
            setAcceptCookie(enable)
            setAcceptThirdPartyCookies(this@RocketWebView, enable)
        }
    }

    override fun enableReaderMode(enable: Boolean) {
        if (enable) {
            if (!inReaderMode) {
                enableMozReaderMode {
                    replaceWithReaderModeBody { txt ->
                        //do
                        LOG.d("reader mode text $txt")
                    }
                }

                updateCssStyle()
                inReaderMode = true
            }

        } else {
            if (inReaderMode) {
                disableReaderMode()
                inReaderMode = false
            }
        }
    }

    override fun updateDarkMode(darkMode: Int) {
        if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
            WebSettingsCompat.setForceDarkStrategy(
                settings, WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY
            )
        }

        if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
            when (darkMode) {
                SettingConstants.DarkModeDisabled -> {
                    WebSettingsCompat.setForceDark(settings, WebSettingsCompat.FORCE_DARK_OFF)
                }

                SettingConstants.DarkModeForceDark -> {
                    WebSettingsCompat.setForceDark(settings, WebSettingsCompat.FORCE_DARK_ON)
                }

                else -> {
                    when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
                        Configuration.UI_MODE_NIGHT_YES -> {
                            WebSettingsCompat.setForceDark(
                                settings, WebSettingsCompat.FORCE_DARK_ON
                            )
                        }

                        else -> {
                            WebSettingsCompat.setForceDark(
                                settings, WebSettingsCompat.FORCE_DARK_OFF
                            )
                        }
                    }
                }
            }
        }

        if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
            WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings, true)
        }

    }

    override fun updateUserAgent(userAgent: String) {
        settings.userAgentString = userAgent
    }

    override fun updateFontSize(fontSize: Int) {
        settings.textZoom = fontSize
    }

    override fun updateImageMode(imageMode: Int) {
        when (imageMode) {
            SettingConstants.ImageModeEnabled -> {
                settings.loadsImagesAutomatically = true
                settings.blockNetworkImage = false
            }

            SettingConstants.ImageModeAuto -> {
                settings.loadsImagesAutomatically = true
                settings.blockNetworkImage = true
            }

            SettingConstants.ImageModeBlock -> {
                settings.loadsImagesAutomatically = false
                settings.blockNetworkImage = true
            }
        }
    }

    override fun isAtTop(): Boolean {
        return scrollY == 0
    }

    private fun enableMozReaderMode(postAction: (() -> Unit)? = null) {
        injectCss(getReaderCss())
        eval(getReaderModeJs()) {
            webContentScrollTop()
            postAction?.invoke()
        }
    }

    // only works in isReadModeOn
    suspend fun getRawText() = suspendCoroutine { continuation ->
        if (!config.readerMode) {
            enableMozReaderMode {
                getReaderModeBodyText { text ->
                    LOG.d("ReaderMode", "fetch body text $text")
                    continuation.resume(
                        text.substring(
                            1, text.length - 2
                        )
                    )
                }
            }
        } else {
            eval(
                "(function() { return document.getElementsByTagName('html')[0].innerText; })();"
            ) { text ->
                val processedText = if (text.startsWith("\"") && text.endsWith("\"")) {
                    text.substring(1, text.length - 2)
                } else text
                continuation.resume(processedText)
            }
        }
    }

    override fun reload() {
        settings.cacheMode = WebSettings.LOAD_DEFAULT
        settings.textZoom = config.fontSize
        inReaderMode = false
        super.reload()
    }

    override fun goBack() {
        settings.textZoom = config.fontSize
        inReaderMode = false
        super.goBack()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        QMUISkinManager.defaultInstance(context).addSkinChangeListener(skinChangeListener)
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        QMUISkinManager.defaultInstance(context).removeSkinChangeListener(skinChangeListener)
    }
}